//
//  BAClassInfo.m
//  BAClassUtil
//
//  Created by pdc on 2017/9/24.
//  Copyright © 2017年 RealsCloud. All rights reserved.
//

#import "BAClassInfo.h"
#import "BAClassCache.h"
#import <objc/runtime.h>

@interface BAClassInfo()
@property (nonatomic, strong, readwrite) NSArray<BAPropertyInfo *> *propertys;
@property (nonatomic, strong, readwrite) NSArray<BAProtocolInfo *> *protocols;
@property (nonatomic, strong, readwrite) NSArray<BAMethodInfo *> *methods;
@property (nonatomic, strong, readwrite) NSArray<BAIvarInfo *> *ivars;
@end

@implementation BAClassInfo
+(instancetype )ClassInfoWithClass:(Class)cls
{
    BAClassInfo *classInfo = [BAClassCache classInfoFrom:cls];
    if (classInfo == nil)
    {
        return [[BAClassInfo alloc] initWithClass:cls];
    }
    return classInfo;
}

-(instancetype )initWithClass:(Class)cls
{
    NSAssert(cls != nil, @"class can't be nil");
    if (self = [super init])
    {
        self->_cls = cls;
        self->_supercls = [cls superclass];
        if (self.supercls)
        {
            self->_superClassInfo = [BAClassInfo ClassInfoWithClass:self.supercls];
        }
        [self parsingClass:cls];
        [BAClassCache saveClassInfo:self];
    }
    return self;
}

-(void )parsingClass:(Class )cls
{
    //property
    [self parsingProperty:cls];
    
    //protocol
    [self parsingProtocol:cls];
    
    //method
    [self parsingMethod:cls];
    
    //ivar
    [self parsingIvar:cls];
}

/**
 * 解析property
 */
-(void )parsingProperty:(Class )cls
{
    NSMutableArray<BAPropertyInfo *> *propertyInfos = [NSMutableArray array];
    unsigned propertyCount;
    objc_property_t *propertyList = class_copyPropertyList(cls, &propertyCount);
    for (unsigned i = 0; i < propertyCount; ++i)
    {
        BAPropertyInfo *propertyInfo = [BAPropertyInfo PropertyInfoWith:propertyList[i]];
        [propertyInfos addObject:propertyInfo];
    }
    free(propertyList);
    self.propertys = [propertyInfos copy];
}

/**
 * 解析protocol
 */
-(void )parsingProtocol:(Class )cls
{
    NSMutableArray<BAProtocolInfo *> *protocolInfos = [NSMutableArray array];
    unsigned protocolCount;
    Protocol * __unsafe_unretained * p_protocol = class_copyProtocolList(cls, &protocolCount);
    if (p_protocol != NULL)
    {
        for (unsigned i = 0; i < protocolCount; ++i)
        {
            BAProtocolInfo *protocolInfo = [BAProtocolInfo ProtocolInfoWith:p_protocol[i]];
            [protocolInfos addObject:protocolInfo];
        }
    }
    free(p_protocol);
    self.protocols = [protocolInfos copy];
}

/**
 * 解析method
 */
-(void )parsingMethod:(Class )cls
{
    NSMutableArray<BAMethodInfo *> *methodInfos = [NSMutableArray array];
    unsigned methodCount = 0;
    Method *p_method = class_copyMethodList(cls, &methodCount);
    for (unsigned i = 0; i < methodCount; ++i)
    {
        BAMethodInfo *methodInfo = [BAMethodInfo MethodInfoWith:p_method[i]];
        [methodInfos addObject:methodInfo];
    }
    free(p_method);
    self.methods = [methodInfos copy];
}

/**
 * 解析ivar
 */
-(void )parsingIvar:(Class )cls
{
    NSMutableArray<BAIvarInfo *> *ivars = [NSMutableArray array];
    unsigned ivarCount = 0;
    Ivar *p_ivar = class_copyIvarList(cls, &ivarCount);
    for (unsigned i = 0; i < ivarCount; ++i)
    {
        BAIvarInfo *ivarInfo = [BAIvarInfo IvarInfoWIth:p_ivar[i]];
        [ivars addObject:ivarInfo];
    }
    free(p_ivar);
    self.ivars = [ivars copy];
}
@end
